using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 抽象对象池基类
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
public abstract class AbstractPool<T> : IPool<T> where T : class
{
    protected Queue<T> m_Pool = new Queue<T>();
    protected IPoolFactory<T> m_Factory;
    protected int m_MaxSize;
    protected int m_InitialSize;
    
    public int Count => m_Pool.Count;
    public int ActiveCount { get; protected set; }
    
    protected AbstractPool(IPoolFactory<T> factory, int initialSize = 10, int maxSize = 100)
    {
        m_Factory = factory;
        m_InitialSize = initialSize;
        m_MaxSize = maxSize;
        InitializePool();
    }
    
    /// <summary>
    /// 初始化池
    /// </summary>
    protected virtual void InitializePool()
    {
        for (int i = 0; i < m_InitialSize; i++)
        {
            var obj = m_Factory.Create();
            Return(obj);
        }
    }
    
    /// <summary>
    /// 获取对象
    /// </summary>
    public virtual T Get()
    {
        T obj = null;
        
        if (m_Pool.Count > 0)
        {
            obj = m_Pool.Dequeue();
        }
        else
        {
            if (ActiveCount >= m_MaxSize)
            {
                Logger.LogWarning("AbstractPool", $"Pool is full ({typeof(T)})");
                return null;
            }
            
            obj = m_Factory.Create();
        }
        
        if (obj != null)
        {
            ActiveCount++;
            OnObjectSpawned(obj);
        }
        
        return obj;
    }
    
    /// <summary>
    /// 归还对象
    /// </summary>
    public virtual void Return(T obj)
    {
        if (obj == null) return;
        
        if (m_Pool.Count >= m_MaxSize)
        {
            m_Factory.Destroy(obj);
            return;
        }
        
        m_Factory.Reset(obj);
        m_Pool.Enqueue(obj);
        ActiveCount--;
        OnObjectReturned(obj);
    }
    
    /// <summary>
    /// 清理池
    /// </summary>
    public virtual void Clear()
    {
        while (m_Pool.Count > 0)
        {
            var obj = m_Pool.Dequeue();
            m_Factory.Destroy(obj);
        }
        ActiveCount = 0;
    }
    
    /// <summary>
    /// 对象从池中取出时调用
    /// </summary>
    protected virtual void OnObjectSpawned(T obj)
    {
        if (obj is IPoolable poolable)
        {
            poolable.OnSpawn();
        }
    }
    
    /// <summary>
    /// 对象归还到池中时调用
    /// </summary>
    protected virtual void OnObjectReturned(T obj)
    {
        if (obj is IPoolable poolable)
        {
            poolable.OnDespawn();
        }
    }
}
